package edu.hawaii.myisern.model;

import java.util.ArrayList;
import java.util.List;

/**
 * Main object providing access to ISERN data.
 * 
 * @author Randy Cox
 * 
 */
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
public class Model {

  /** The singleton StackModel instance. */
  private static Model theInstance = new Model();

  /** Private constructor used to create a single instance of stack. */
  private Model() {
  }

  /**
   * Get the single instance of the Model object.
   * 
   * @return Model instance.
   */
  public static Model getInstance() {
    return Model.theInstance;
  }

  /**
   * Retrieve researcher.
   * 
   * @param name of researcher.
   * @return researcher retrieved.
   */
  public MyResearcher getResearcher(String name) {
    DatabaseResearchers dbResearchers = new DatabaseResearchers();
    MyResearcher myResearcher = dbResearchers.get(name);
    return myResearcher;
  }

  /**
   * Retrieve organization.
   * 
   * @param name of organization.
   * @return organization retrieved.
   */
  public MyOrganization getOrganization(String name) {
    DatabaseOrganizations dbOrganizations = new DatabaseOrganizations();
    MyOrganization myOrganization = dbOrganizations.get(name);
    return myOrganization;
  }

  /**
   * Retrieve collaboration.
   * 
   * @param name of collaboration.
   * @return collaboration retrieved.
   */
  public MyCollaboration getCollaboration(String name) {
    DatabaseCollaborations dbCollaborations = new DatabaseCollaborations();
    MyCollaboration myCollaboration = dbCollaborations.get(name);
    return myCollaboration;
  }

  /**
   * Saves the researcher.
   * 
   * @param myResearcher record to save.
   */
  public void saveResearcher(MyResearcher myResearcher) {
    DatabaseResearchers dbResearchers = new DatabaseResearchers();
    dbResearchers.save(myResearcher);
  }

  /**
   * Saves the organization.
   * 
   * @param myOrganization record to save.
   */
  public void saveOrganization(MyOrganization myOrganization) {
    DatabaseOrganizations dbOrganizations = new DatabaseOrganizations();
    dbOrganizations.save(myOrganization);
  }

  /**
   * Saves the collaboration.
   * 
   * @param myCollaboration record to save.
   */
  public void saveCollaboration(MyCollaboration myCollaboration) {
    DatabaseCollaborations dbCollaborations = new DatabaseCollaborations();
    dbCollaborations.save(myCollaboration);
  }

  /**
   * Delete researcher.
   * 
   * @param name of researcher.
   */
  public void deleteResearcher(String name) {
    DatabaseResearchers dbResearchers = new DatabaseResearchers();
    dbResearchers.delete(name);
  }

  /**
   * Delete organization.
   * 
   * @param name of organization.
   */
  public void deleteOrganization(String name) {
    DatabaseOrganizations dbOrganizations = new DatabaseOrganizations();
    dbOrganizations.delete(name);
  }

  /**
   * Delete collaboration.
   * 
   * @param name of collaboration.
   */
  public void deleteCollaboration(String name) {
    DatabaseCollaborations dbCollaborations = new DatabaseCollaborations();
    dbCollaborations.delete(name);
  }

  /**
   * List researchers.
   * 
   * @return 2-D List of researchers.
   */
  public List<MyResearcher> listResearchers() {
    DatabaseResearchers dbResearchers = new DatabaseResearchers();
    return dbResearchers.list();
  }

  /**
   * List organizations.
   * 
   * @return List of organizations.
   */
  public List<MyOrganization> listOrganizations() {
    DatabaseOrganizations dbOrganizations = new DatabaseOrganizations();
    return dbOrganizations.list();
  }

  /**
   * List collaborations.
   * 
   * @return List of collaborations.
   */
  public List<MyCollaboration> listCollaborations() {
    DatabaseCollaborations dbCollaborations = new DatabaseCollaborations();
    return dbCollaborations.list();
  }

  /**
   * Import researchers.
   * 
   * @param filename to import.
   */
  public void importResearchers(String filename) {
    Log.enter("Model.importResearchers start.");
    Log.enter("Filename =" + filename);
    List<MyResearcher> list = null;
    try {
      list = DataXml.readXmlResearchers(filename);
      Integer count = list.size();
      Log.enter("Uploaded from file =" + count.toString());
    }
    catch (Exception e) {
      Log.error("Model.importResearchers filename = " + filename + " " + e.getMessage());
    }
    if (list != null) {
      for (MyResearcher item : list) {
        Model.getInstance().saveResearcher(item);
        Log.enter("Uploading reocord =" + item.getName());
      }
    }
  }

  /**
   * Import organizations.
   * 
   * @param filename to import.
   */
  public void importOrganizations(String filename) {
    Log.enter("Model.importOrganizations start.");
    Log.enter("Filename =" + filename);
    List<MyOrganization> list = null;
    try {
      list = DataXml.readXmlOrganizations(filename);
      Integer count = list.size();
      Log.enter("Uploaded from file =" + count.toString());
    }
    catch (Exception e) {
      Log.error("Model.importOrganizations filename=" + filename);
    }
    if (list != null) {
      for (MyOrganization item : list) {
        Model.getInstance().saveOrganization(item);
        Log.enter("Uploading reocord =" + item.getName());
      }
    }
  }

  /**
   * Import collaborations.
   * 
   * @param filename to import.
   */
  public void importCollaborations(String filename) {
    Log.enter("Model.importCollaborations start.");
    Log.enter("Filename =" + filename);
    List<MyCollaboration> list = null;
    try {
      list = DataXml.readXmlCollaborations(filename);
      Integer count = list.size();
      Log.enter("Uploaded from file =" + count.toString());
    }
    catch (Exception e) {
      Log.error("Model.importCollaborations filename=" + filename);
    }
    if (list != null) {
      for (MyCollaboration item : list) {
        Model.getInstance().saveCollaboration(item);
        Log.enter("Uploading reocord =" + item.getName());
      }
    }
  }

  /**
   * Export researchers.
   * 
   * @param filename to import.
   */
  public void exportResearchers(String filename) {
    Log.enter("Model.exportResearchers start.");
    Log.enter("Filename =" + filename);
    try {
      DataXml.writeXmlResearchers(filename, this.listResearchers());
      Log.enter("Downloaded to file succesfully.");
    }
    catch (Exception e) {
      Log.error("Model.exportResearchers filename=" + filename);
    }
  }

  /**
   * Export organizations.
   * 
   * @param filename to import.
   */
  public void exportOrganizations(String filename) {
    Log.enter("Model.exportOrganizations start.");
    Log.enter("Filename =" + filename);
    try {
      DataXml.writeXmlOrganizations(filename, this.listOrganizations());
      Log.enter("Downloaded to file succesfully.");
    }
    catch (Exception e) {
      Log.error("Model.exportOrganizations filename=" + filename);
    }
  }

  /**
   * Export Collaborations.
   * 
   * @param filename to import.
   */
  public void exportCollaborations(String filename) {
    Log.enter("Model.exportCollaborations start.");
    Log.enter("Filename =" + filename);
    try {
      DataXml.writeXmlCollaborations(filename, this.listCollaborations());
      Log.enter("Downloaded to file succesfully.");
    }
    catch (Exception e) {
      Log.error("Model.exportCollaborations filename=" + filename);
    }
  }

  /**
   * Clear researchers.
   * 
   */
  public void clearResearchers() {
    DatabaseResearchers db = new DatabaseResearchers();
    db.clear();
  }

  /**
   * Clear organizations.
   * 
   */
  public void clearOrganizations() {
    DatabaseOrganizations db = new DatabaseOrganizations();
    db.clear();
  }

  /**
   * Clear collaborations.
   * 
   */
  public void clearCollaborations() {
    DatabaseCollaborations db = new DatabaseCollaborations();
    db.clear();
  }

  /**
   * Researcher semantic check.
   * 
   * @return 2-d list of errors from semantic check.
   */
  public List<List<String>> researcherCheck() {
    List<List<String>> table = new ArrayList<List<String>>();
    DatabaseResearchers dbResearchers = new DatabaseResearchers();
    DatabaseOrganizations dbOrganizations = new DatabaseOrganizations();

    // Get researcher errors.
    List<MyResearcher> listResearchers = dbResearchers.list();
    for (MyResearcher row : listResearchers) {
      String orgId = Id.build(row.getOrganization());
      if (!dbOrganizations.hasOrganization(orgId)) {
        List<String> list = new ArrayList<String>();
        list.add("organization");
        list.add(row.getName());
        list.add(row.getOrganization());
        table.add(list);
        Log.enter("Model.semanticCheck() reseacher error = " + row.getName());
      }
    }
    return table;
  }

  /**
   * Organization semantic check.
   * 
   * @return 2-d list of errors from semantic check.
   */
  public List<List<String>> organizationCheck() {
    List<List<String>> table = new ArrayList<List<String>>();
    DatabaseResearchers dbResearchers = new DatabaseResearchers();
    DatabaseOrganizations dbOrganizations = new DatabaseOrganizations();

    // Get organization errors.
    List<MyOrganization> listOrganizations = dbOrganizations.list();
    for (MyOrganization row : listOrganizations) {

      // Check contact.
      String contactId = Id.build(row.getContact());
      if (!dbResearchers.hasResearcher(contactId)) {
        List<String> list = new ArrayList<String>();
        list.add("contact");
        list.add(row.getName());
        list.add(row.getContact());
        table.add(list);
        Log.enter("Model.semanticCheck() organization-contact error = " + list.get(1));
      }

      // Check affiliated researchers.
      for (String reasName : row.getAffiliatedResearchers()) {
        String reasId = Id.build(reasName);
        if (!dbResearchers.hasResearcher(reasId)) {
          List<String> list = new ArrayList<String>();
          list.add("affiliated researcher");
          list.add(row.getName());
          list.add(reasName);
          table.add(list);
          Log.enter("Model.semanticCheck() organization-affiliated reas error = " + list.get(1));
        }
      }
    }
    return table;
  }

  /**
   * Collaboration semantic check.
   * 
   * @return 2-d list of errors from semantic check.
   */
  public List<List<String>> collaborationCheck() {
    List<List<String>> table = new ArrayList<List<String>>();
    DatabaseOrganizations dbOrganizations = new DatabaseOrganizations();
    DatabaseCollaborations dbCollaborations = new DatabaseCollaborations();

    // Get Collaboration errors.
    List<MyCollaboration> listCollaborations = dbCollaborations.list();
    for (MyCollaboration row : listCollaborations) {

      // Check affiliated contributing organizations.
      for (String orgName : row.getOrganizations()) {
        String orgId = Id.build(orgName);
        if (!dbOrganizations.hasOrganization(orgId)) {
          List<String> list = new ArrayList<String>();
          list.add("collaborating organization");
          list.add(row.getName());
          list.add(orgName);
          table.add(list);
          Log.enter("Model.semanticCheck() collaboration error = " + list.get(1));
        }
      }
    }
    return table;
  }
}
